﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Input;
using Security.Events.Commands;
using Security.Events.Repositories;
using Security.Helpers;

namespace Security.Events.Handlers
{
    [Export(typeof(CommandHandler))]
    public class CommitChangesCommandHandler : CommandHandler
    {
        private readonly IEnumerable<Lazy<IRepository, IRepositoryMetadata>> repositories;

        [ImportingConstructor]
        public CommitChangesCommandHandler(EventBroker eventBroker, 
                                           [ImportMany] IEnumerable<Lazy<IRepository, IRepositoryMetadata>> repositories) 
            : base(eventBroker)
        {
            this.repositories = repositories;
        }

        protected override void Subscribe()
        {
            eventBroker.OfType<CommitChangesCommand>().Subscribe(OnCommitChanges);
        }

        private void OnCommitChanges(CommitChangesCommand command)
        {
            var type = command.Tags.First().GetType();
            var tags = command.Tags;
            if (tags.Any(t => t.GetType() != type))
                throw new InvalidOperationException("Все обьекты отправляемые в БД должны быть одного типа");

            var lazyRepository = repositories.FirstOrDefault(r => type.IsBaseOf(r.Metadata.Type));
            if (lazyRepository == null)
                throw new InvalidOperationException(string.Format("Не сопоставлен репозиторий для типа {0}", type.Name));

            using (CursorScope.With(Cursors.Wait))
            {
                var repository = lazyRepository.Value;
                command.Operation.Match(Operation.Insert, () => repository.InsertObjects(tags)).
                    Match(Operation.Change, () => repository.ChangeObjects(tags)).
                    Match(Operation.Delete, () => repository.DeleteObjects(tags));
            }

            var changesCommitedCommand = new ChangesCommittedCommand(command.Operation, command.Tags);
            command.AppendToSession(changesCommitedCommand.SessionId);
            eventBroker.Publish(changesCommitedCommand);
        }
    }
}
